//
// @Author: Zhenwei Xiao
// @Description:
// @Version: 1.0.0
// @Date: 2021/2/26 上午9:56
// @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
//


const sm2 = require("sm-crypto").sm2;
// const uti = require("../utils")


//
// 对空值和曲线参数匹配进行检测
//
// @Description:
// @param priv *Sm2PrivateKey
// @param pub *Sm2PublicKey
// @return bool
//
function IsOnCurve(priv, pub) {
	if (pub === null || priv === null || pub.PublicKey === null || priv.PrivateKey === null ){
		return false
	}
	return priv.PrivateKey.IsOnCurve(pub.PublicKey.X, pub.PublicKey.Y)
}

//
// 随机生成一对公私钥
//
// @Description:
// @return Sm2PrivateKey
// @return Sm2PublicKey
//
function GenKeyPair() {
    let keypair = sm2.generateKeyPairHex()
    var pub = keypair.publicKey // 公钥
    var prk = keypair.privateKey // 私钥
	var prik = new Sm2PrivateKey(prk)
	var pubk = new Sm2PublicKey(pub)
	for (;;){
        if(pubk.GetBytes().length != 130){
            keypair = sm2.generateKeyPairHex()
            pub = keypair.publicKey // 公钥
            prk = keypair.privateKey // 私钥
            prik = new Sm2PrivateKey(prk)
            pubk = new Sm2PublicKey(pub)
        }else{
            break
        }
	}
	return [prik, pubk]
}

//二次封装的sm2私钥
class Sm2PrivateKey {
	constructor(prk) 
    {
        this.PrivateKey = prk
    }
    //
    // 获取私钥的字节表示
    //
    // @Description:
    // @return []byte
    //
    GetBytes() {
        const uti = require("../utils")
        return uti.Str2Bytes(this.PrivateKey)
    }

    //
    // 根据所给字节设置私钥
    //
    // @Description:
    // @param priBytes []byte
    // @return bool
    //
    SetBytes(priBytes) {
        const uti = require("../utils")
        if (uti.Bytes2Str(priBytes).length !=64) {
            return new Error("设置私钥长度错误").message
        }
        let pri = uti.Bytes2Str(priBytes)

        this.PrivateKey = pri
        return null
    }

    //
    // 私钥解密
    //
    // @Description:
    // @param msg []byte
    // @param opt com.DecrypterOpts
    // @return plaintext []byte
    // @return err error
    //
    Decrypt(msg, opts)  {
        const uti = require("../utils")
        let cipherMode = opts
        msg = uti.Bytes2Str(msg)
        try {
            return [uti.Str2Bytes(sm2.doDecrypt(msg, this.PrivateKey, cipherMode)), null]
        }catch(err){
            return [null, err.message]
        }
    }

    //
    // 私钥签名
    //
    // @Description:
    // @param digest []byte
    // @param opt com.SignerOpts
    // @return plaintext []byte
    // @return err error
    //
    Sign(digest, opts) {
        const uti = require("../utils")
        digest = uti.Bytes2Str(digest)
        try{
            return [uti.Str2Bytes(sm2.doSignature(digest, this.PrivateKey)), null]
        }catch(err){
            return [null, err.message]
        }
    }
}

//封装的sm2公钥
class Sm2PublicKey {
    constructor(pub) 
    {
        this.PublicKey = pub
    }
    //
    // 获取公钥的字节表示
    //
    // @Description:
    // @return []byte
    //
    GetBytes() {
        const uti = require("../utils")
        return uti.Str2Bytes(this.PublicKey)
    }

    //
    // 根据所给字节设置公钥
    //
    // @Description:
    // @param pubBytes []byte
    // @return bool
    //
    SetBytes(pubBytes) {
        const uti = require("../utils")
        if (uti.Bytes2Str(pubBytes).length != 130 ){
            return new Error("设置公钥长度错误").message
        }
        try{
            let data = uti.Bytes2Str(pubBytes)
            let x = data.substring(2,66).toString(16)
            let y = data.substring(66,130).toString(16)
            this.PublicKey = '04' + x + y
        }catch(err){
            return err.message
        }
        return null
    }

    //
    // 公钥加密
    //
    // @Description:
    // @param msg []byte
    // @param opt com.DecrypterOpts
    // @return encryptedtext []byte
    // @return err error
    //
    Encrypt(msg, opts)  {
        const uti = require("../utils")
        let cipherMode = opts
        msg = uti.Bytes2Str(msg)
        try {
            return [uti.Str2Bytes(sm2.doEncrypt(msg, this.PublicKey, cipherMode)), null]
        }catch(err){
            return [null, err.message]
        }
    }

    //
    // 公钥验证
    //
    // @Description:
    // @param msg []byte
    // @param sign []byte
    // @param opt com.SignerOpts
    // @return bool 
    // @return error
    //
    Verify(msg, sign, opts)  {
        const uti = require("../utils")
        msg = uti.Bytes2Str(msg)
        try{
            return [sm2.doVerifySignature(msg, sign, this.PublicKey), null]
        }catch(err){
            return [null, err.message]
        }
    }
}

module.exports = {
    GenKeyPair: GenKeyPair,
    Sm2PrivateKey: Sm2PrivateKey,
    Sm2PublicKey: Sm2PublicKey
}


